1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
19 $Log: Mac\040OS\040Test\040Responder.c,v $
20 Revision 1.25 2006/08/14 23:24:29 cheshire
21 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
23 Revision 1.24 2004/12/16 20:49:34 cheshire
24 <rdar://problem/3324626> Cache memory management improvements
26 Revision 1.23 2004/09/17 01:08:50 cheshire
27 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
28 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
29 declared in that file are ONLY appropriate to single-address-space embedded applications.
30 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
32 Revision 1.22 2004/08/13 23:25:01 cheshire
33 Now that we do both uDNS and mDNS, global replace "m->hostname" with
34 "m->MulticastHostname" for clarity
36 Revision 1.21 2004/03/12 21:30:25 cheshire
37 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
38 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
40 Revision 1.20 2004/02/09 23:23:32 cheshire
41 Advertise "IL 2\4th Floor.apple.com." as another test "browse domain"
43 Revision 1.19 2004/01/24 23:55:15 cheshire
44 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
46 Revision 1.18 2003/11/14 21:27:08 cheshire
47 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
48 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
50 Revision 1.17 2003/08/14 02:19:54 cheshire
51 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
53 Revision 1.16 2003/08/12 19:56:24 cheshire
58 #include <stdio.h> // For printf()
59 #include <string.h> // For strlen() etc.
61 #include <Events.h> // For WaitNextEvent()
62 #include <SIOUX.h> // For SIOUXHandleOneEvent()
64 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
66 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
68 // These don't have to be globals, but their memory does need to remain valid for as
69 // long as the search is going on. They are declared as globals here for simplicity.
71 static mDNS_PlatformSupport p
;
72 static ServiceRecordSet p1
, p2
, afp
, http
, njp
;
73 static AuthRecord browsedomain1
, browsedomain2
;
75 // This sample code just calls mDNS_RenameAndReregisterService to automatically pick a new
76 // unique name for the service. For a device such as a printer, this may be appropriate.
77 // For a device with a user interface, and a screen, and a keyboard, the appropriate
78 // response may be to prompt the user and ask them to choose a new name for the service.
79 mDNSlocal
void Callback(mDNS
*const m
, ServiceRecordSet
*const sr
, mStatus result
)
83 case mStatus_NoError
: debugf("Callback: %##s Name Registered", sr
->RR_SRV
.resrec
.name
->c
); break;
84 case mStatus_NameConflict
: debugf("Callback: %##s Name Conflict", sr
->RR_SRV
.resrec
.name
->c
); break;
85 case mStatus_MemFree
: debugf("Callback: %##s Memory Free", sr
->RR_SRV
.resrec
.name
->c
); break;
86 default: debugf("Callback: %##s Unknown Result %d", sr
->RR_SRV
.resrec
.name
->c
, result
); break;
89 if (result
== mStatus_NameConflict
) mDNS_RenameAndReregisterService(m
, sr
, mDNSNULL
);
92 // RegisterService() is a simple wrapper function which takes C string
93 // parameters, converts them to domainname parameters, and calls mDNS_RegisterService()
94 mDNSlocal
void RegisterService(mDNS
*m
, ServiceRecordSet
*recordset
,
95 UInt16 PortAsNumber
, const char txtinfo
[],
96 const domainlabel
*const n
, const char type
[], const char domain
[])
100 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
101 UInt8 txtbuffer
[512];
103 MakeDomainNameFromDNSNameString(&t
, type
);
104 MakeDomainNameFromDNSNameString(&d
, domain
);
108 strncpy((char*)txtbuffer
+1, txtinfo
, sizeof(txtbuffer
)-1);
109 txtbuffer
[0] = (UInt8
)strlen(txtinfo
);
114 mDNS_RegisterService(m
, recordset
,
115 n
, &t
, &d
, // Name, type, domain
116 mDNSNULL
, mDNSOpaque16fromIntVal(PortAsNumber
),
117 txtbuffer
, (mDNSu16
)(1+txtbuffer
[0]), // TXT data, length
118 mDNSNULL
, 0, // Subtypes (none)
119 mDNSInterface_Any
, // Interface ID
120 Callback
, mDNSNULL
); // Callback and context
122 ConvertDomainNameToCString(recordset
->RR_SRV
.resrec
.name
, buffer
);
123 printf("Made Service Records for %s\n", buffer
);
126 // RegisterFakeServiceForTesting() simulates the effect of services being registered on
127 // dynamically-allocated port numbers. No real service exists on that port -- this is just for testing.
128 mDNSlocal
void RegisterFakeServiceForTesting(mDNS
*m
, ServiceRecordSet
*recordset
, const char txtinfo
[],
129 const char name
[], const char type
[], const char domain
[])
131 static UInt16 NextPort
= 0xF000;
133 MakeDomainLabelFromLiteralString(&n
, name
);
134 RegisterService(m
, recordset
, NextPort
++, txtinfo
, &n
, type
, domain
);
137 // CreateProxyRegistrationForRealService() checks to see if the given port is currently
138 // in use, and if so, advertises the specified service as present on that port.
139 // This is useful for advertising existing real services (Personal Web Sharing, Personal
140 // File Sharing, etc.) that currently don't register with mDNS Service Discovery themselves.
141 mDNSlocal OSStatus
CreateProxyRegistrationForRealService(mDNS
*m
, UInt16 PortAsNumber
, const char txtinfo
[],
142 const char *servicetype
, ServiceRecordSet
*recordset
)
147 TEndpointInfo endpointinfo
;
148 EndpointRef ep
= OTOpenEndpoint(OTCreateConfiguration(kTCPName
), 0, &endpointinfo
, &err
);
149 if (!ep
|| err
) { printf("OTOpenEndpoint (CreateProxyRegistrationForRealService) failed %d", err
); return(err
); }
151 ia
.fAddressType
= AF_INET
;
152 ia
.fPort
= mDNSOpaque16fromIntVal(PortAsNumber
).NotAnInteger
;
154 bindReq
.addr
.maxlen
= sizeof(ia
);
155 bindReq
.addr
.len
= sizeof(ia
);
156 bindReq
.addr
.buf
= (UInt8
*)&ia
;
158 err
= OTBind(ep
, &bindReq
, NULL
);
160 if (err
== kOTBadAddressErr
)
161 RegisterService(m
, recordset
, PortAsNumber
, txtinfo
, &m
->nicelabel
, servicetype
, "local.");
163 debugf("OTBind failed %d", err
);
169 // Done once on startup, and then again every time our address changes
170 mDNSlocal OSStatus
mDNSResponderTestSetup(mDNS
*m
)
172 char buffer
[MAX_ESCAPED_DOMAIN_NAME
];
173 mDNSv4Addr ip
= m
->HostInterfaces
->ip
.ip
.v4
;
175 ConvertDomainNameToCString(&m
->MulticastHostname
, buffer
);
176 printf("Name %s\n", buffer
);
177 printf("IP %d.%d.%d.%d\n", ip
.b
[0], ip
.b
[1], ip
.b
[2], ip
.b
[3]);
180 printf("Registering Service Records\n");
181 // Create example printer discovery records
182 //static ServiceRecordSet p1, p2;
186 RegisterFakeServiceForTesting(m
, &p1
, "path=/index.html", "Web Server One", "_http._tcp.", "local.");
187 RegisterFakeServiceForTesting(m
, &p2
, "path=/path.html", "Web Server Two", "_http._tcp.", "local.");
189 RegisterFakeServiceForTesting(m
, &p1
, "rn=lpq1", "Epson Stylus 900N", "_printer._tcp.", "local.");
190 RegisterFakeServiceForTesting(m
, &p2
, "rn=lpq2", "HP LaserJet", "_printer._tcp.", "local.");
192 RegisterFakeServiceForTesting(m
, &p1
, "rn=lpq3", "My Printer", "_printer._tcp.", "local.");
193 RegisterFakeServiceForTesting(m
, &p2
, "lrn=pq4", "My Other Printer", "_printer._tcp.", "local.");
196 // If AFP Server is running, register a record for it
197 CreateProxyRegistrationForRealService(m
, 548, "", "_afpovertcp._tcp.", &afp
);
199 // If Web Server is running, register a record for it
200 CreateProxyRegistrationForRealService(m
, 80, "", "_http._tcp.", &http
);
202 // And pretend we always have an NJP server running on port 80 too
203 //RegisterService(m, &njp, 80, "NJP/", &m->nicelabel, "_njp._tcp.", "local.");
205 // Advertise that apple.com. is available for browsing
206 mDNS_AdvertiseDomains(m
, &browsedomain1
, mDNS_DomainTypeBrowse
, mDNSInterface_Any
, "apple.com.");
207 mDNS_AdvertiseDomains(m
, &browsedomain2
, mDNS_DomainTypeBrowse
, mDNSInterface_Any
, "IL 2\\4th Floor.apple.com.");
212 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
213 mDNSlocal Boolean
YieldSomeTime(UInt32 milliseconds
)
215 extern Boolean SIOUXQuitting
;
217 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
218 SIOUXHandleOneEvent(&e
);
219 return(SIOUXQuitting
);
225 Boolean DoneSetup
= false;
227 SIOUXSettings
.asktosaveonclose
= false;
228 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Responder";
230 printf("Multicast DNS Responder\n\n");
231 printf("This software reports errors using MacsBug breaks,\n");
232 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
233 printf("******************************************************************************\n");
235 err
= InitOpenTransport();
236 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
238 err
= mDNS_Init(&m
, &p
, mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
239 mDNS_Init_AdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
240 if (err
) return(err
);
242 while (!YieldSomeTime(35))
244 #if MDNS_ONLYSYSTEMTASK
245 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
246 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
247 extern void mDNSPlatformIdle(mDNS
*const m
);
248 mDNSPlatformIdle(&m
); // Only needed for debugging version
250 if (m
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
253 printf("\nListening for mDNS queries...\n");
254 mDNSResponderTestSetup(&m
);
258 if (p1
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p1
);
259 if (p2
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &p2
);
260 if (afp
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &afp
);
261 if (http
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &http
);
262 if (njp
.RR_SRV
.resrec
.RecordType
) mDNS_DeregisterService(&m
, &njp
);